import RcMenu from "rc-menu";
import RcTrigger from "rc-trigger";
import React, { useContext, useEffect, useRef, useState } from "react";
import TagOption from "./TagOption";
import Input, { RefInputProps } from "./Input";
import { createUseStyles } from "react-jss";
import { ThemeContext } from "../../theme";

export default TagSelect;

const useStyles = createUseStyles({
  fontSize: {
    fontSize: (props: { fontSize: number }) => props.fontSize,
  },
});

const BuiltinPlacements = {
  left: { points: ["cr", "cl"] },
  right: { points: ["cl", "cr"] },
  top: { points: ["bc", "tc"] },
  bottom: { points: ["tc", "bc"] },
  topLeft: { points: ["bl", "tl"] },
  topRight: { points: ["br", "tr"] },
  bottomRight: { points: ["tr", "br"] },
  bottomLeft: { points: ["tl", "bl"] },
};

interface TagSelectProps {
  visible: boolean;
  options: Array<string> | ((text?: string) => Promise<Array<string>>);
  maxLength?: number;
  className?: string;
  onInputChange?: (v: string) => void;
  onChange: (v: string) => void;
  getPopupContainer?: () => HTMLElement;
}

function TagSelect({
  visible,
  className,
  maxLength,
  options: propsOptions = [],
  onInputChange,
  onChange,
  getPopupContainer,
}: TagSelectProps) {
  const { fontSize } = useContext(ThemeContext);
  const classes = useStyles({ fontSize });

  const [value, setValue] = useState("");
  const [innerOption, setInnerOption] = useState<string[]>([]);

  const inputRef = useRef<RefInputProps>(null);

  const handleInputClear = () => inputRef.current?.input("");

  const getOptions = (tag?: string) => {
    if (typeof propsOptions == "function") {
      propsOptions(tag).then((resp) => setInnerOption(resp));
    } else {
      setInnerOption(
        propsOptions.filter((x) => (tag ? x.includes(tag) : true))
      );
    }
  };

  useEffect(() => {
    if (visible) {
      inputRef.current?.focus();
      typeof propsOptions !== "function" && getOptions();
    }
  }, [visible, propsOptions]);

  const handleTagInput = (v: string) => {
    setValue(v);
    getOptions(v);
    onInputChange?.(v);
  };

  //input输入框的blur事件会与RcMenu的onOverlayClick重复触发
  //导致无法点击下拉框
  //onVisibleChange在触发下拉框隐藏时，输入框中存在内容触发onChange达到类似blur的效果
  const addHandler = () => {
    onChange(value);
    setValue("");
    handleInputClear();
  };

  const handleMenuSelect = (e: any) => {
    onChange(e.key);
    setValue("");
    handleInputClear();
  };

  const isNew = value && !innerOption.includes(value);

  const options: Array<string> = isNew ? [value, ...innerOption] : innerOption;

  const menu = (
    <RcMenu
      prefixCls="ct0-tag-menu"
      className={classes.fontSize}
      onSelect={handleMenuSelect}
    >
      {options.map((x) => (
        <RcMenu.Item key={x}>
          <div className="ct0-tag-menu-text">
            {isNew && x == value && (
              <div className="ct0-tag-menu-text-new">
                <b>NEW</b>
              </div>
            )}
            <span className="ct0-tag-menu-text-content">
              <TagOption text={x} keyword={value} />
            </span>
          </div>
        </RcMenu.Item>
      ))}
    </RcMenu>
  );

  return (
    <RcTrigger
      destroyPopupOnHide
      popupVisible={visible}
      action="focus"
      popupPlacement="bottomLeft"
      builtinPlacements={BuiltinPlacements}
      prefixCls="ct0-tag-trigger"
      popup={menu}
      onPopupVisibleChange={(v) => {
        if (v == false) addHandler();
      }}
      getPopupContainer={getPopupContainer}
    >
      <Input
        ref={inputRef}
        value={value}
        maxLength={maxLength}
        onInput={handleTagInput}
        onPressEnter={addHandler}
        className={className}
      />
    </RcTrigger>
  );
}
